package so.sao.code.service.web.portal;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import so.sao.auth.autoreg.annotation.ButtonResource;
import so.sao.auth.autoreg.annotation.MenuResource;
import so.sao.code.dto.request.TagBatchCreate;
import so.sao.code.service.domain.entity.TagBatch;
import so.sao.code.service.infrastructure.enums.CodeMessage;
import so.sao.code.service.infrastructure.enums.PrintFileFormatStatus;
import so.sao.code.service.infrastructure.model.vo.EnterpriseInfoVO;
import so.sao.code.service.infrastructure.model.vo.TagBatchVO;
import so.sao.code.service.infrastructure.model.vo.TagMetaVO;
import so.sao.code.service.infrastructure.utils.BeanUtils;
import so.sao.code.service.service.EnterpriseInfoService;
import so.sao.code.service.service.TagBatchService;
import so.sao.log.feign.aspect.ActionControllerLog;
import so.sao.sso.bind.CurrentUser;
import so.sao.sso.common.CommonConstants;
import so.sao.sso.feign.PortalFeignClient;
import so.sao.sso.feign.dto.UserDTO;
import so.sao.top.core.util.PageUtil;
import so.sao.top.core.util.mapper.JsonMapper;
import so.sao.top.core.util.rest.RestException;
import springfox.documentation.annotations.ApiIgnore;

@Api(tags = "tagbatch", description = "Portal标签批次")
@RestController
@RequestMapping("portal/tagbatch")
@MenuResource(perm = "*", cls = "codeMgmt", order = 10)
@MenuResource(perm = "code.*", url = "code")
public class TagBatchController {

	@Autowired
	private TagBatchService tagBatchService;

	@Autowired
	EntityManager em;
	@Autowired
	PortalFeignClient userClient;
	@Autowired
	EnterpriseInfoService enterpriseInfoService;

	/**
	 * 标签批次创建接口，支持创建目前定义的四种标签
	 *
	 * @param tagBatchCreate
	 * @return
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	@ApiOperation(value = "标签批次创建接口", notes = "同时支持标准码、箱码、套标和卷标创建")
	@ApiImplicitParam(name = "tagBatchCreate", value = "批次创建请求", required = true, dataType = "TagBatchCreate", paramType = "body")
	@PostMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	@ButtonResource(url = "createbatch")
	@RequiresPermissions("code.createbatch")
	@ActionControllerLog(application = ActionControllerLog.Application.CODE, model = ActionControllerLog.Model.BATCH, action = ActionControllerLog.Action.CREATE)
	public ResponseEntity<List<Long>> create(@ApiIgnore @CurrentUser UserDTO user,
											 @Valid @RequestBody TagBatchCreate tagBatchCreate)
			throws IllegalAccessException, InvocationTargetException {

		return new ResponseEntity<>(tagBatchService.create(tagBatchCreate), HttpStatus.CREATED);
	}

	/**
	 * 标签类型状态等元数据
	 */
	@ApiOperation(value = "标签类型状态等元数据", notes = "标签类型状态等元数据")
	@GetMapping(value = "tagMeta")
	@RequiresAuthentication
	public ResponseEntity<TagMetaVO> tagMeta() {
		return new ResponseEntity<>(tagBatchService.getTagMeta(), HttpStatus.OK);
	}

	/**
	 * 标签批次信息查询接口
	 *
	 * @param user
	 * @param request
	 * @return
	 */
	@ApiOperation(value = "标签批次查询接口", notes = "标签批次查询接口，依据当前登录用户所在的企业ID进行查询")
	@GetMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	@RequiresAuthentication
	public Page<TagBatchVO> findAll(@ApiIgnore @CurrentUser UserDTO user, HttpServletRequest request,
									final String tagBatchIdOrName, final Integer type, final Integer formatStatus,
									final Integer associateStatus) {
		EnterpriseInfoVO res = enterpriseInfoService.get(user.getEseId());
		if (res == null) {
			throw new RestException(HttpStatus.NOT_IMPLEMENTED, CodeMessage.EnterpriseInfoError);
		}
		PageRequest pageable = PageUtil.getPageRequest(request);
		Page<TagBatch> orig = null;

		Long factoryId = userClient.findfactoryId(user.getUsername());
		if (factoryId != null) {
			orig = getByFactoryUser(pageable, user, request, tagBatchIdOrName, type, formatStatus, associateStatus,
					factoryId);
		} else {
			Specification<TagBatch> spec = new Specification<TagBatch>() {
				@Override
				public Predicate toPredicate(Root<TagBatch> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
					List<Predicate> predicate = new ArrayList<Predicate>();
					if (user.getEseId() != null & user.getEseId().intValue() != CommonConstants.SYSTEM_INNER_ESEID) {
						predicate.add(cb.equal(root.get("eseId").as(Long.class), user.getEseId()));
					}

					if (StringUtils.isNotBlank(tagBatchIdOrName)) {
						if (StringUtils.isNumeric(tagBatchIdOrName)) {
							Predicate p1 = cb.equal(root.get("id").as(Long.class), Long.valueOf(tagBatchIdOrName));
							Predicate p2 = cb.like(root.get("name").as(String.class), "%" + tagBatchIdOrName + "%");
							predicate.add(cb.or(p1, p2));// tagbatchid
						} else {
							predicate.add(cb.like(root.get("name").as(String.class), "%" + tagBatchIdOrName + "%"));// tagbatchname
						}
					}
					if (type != null) {
						predicate.add(cb.equal(root.get("type").as(Long.class), type));
					}
					if (formatStatus != null) {
						switch (formatStatus) {
							case 1: // 未设置
								predicate.add(root.get("tagBatchConfigId").isNull());
								break;
							case 2: // 已设置
								predicate.add(root.get("tagBatchConfigId").isNotNull());
								break;
							case 3: // 已下载
								predicate.add(cb.equal(root.get("printFileStatus").as(Integer.class),
										PrintFileFormatStatus.Downloaded.getValue()));
								break;
							default:
								break;
						}
					}
					// TODO add associateStatus query condition
					Predicate[] parr = new Predicate[predicate.size()];
					return cb.and(predicate.toArray(parr));
				}
			};
			orig = tagBatchService.findTagBatches(spec, pageable);
		}

		Page<TagBatchVO> result = orig.map(new Converter<TagBatch, TagBatchVO>() {
			@Override
			public TagBatchVO convert(TagBatch source) {
				TagBatchVO dest = new TagBatchVO();
				try {
					BeanUtils.copyProperties(dest, source);
					dest.setType(source.getType().getValue());
					dest.setStatus(source.getStatus().getValue());
				} catch (Exception e) {
					e.printStackTrace();
				}
				return dest;
			}
		});
		tagBatchService.buildTagBatchVO(result.getContent());
		return result;
	}

	@Autowired
	JsonMapper jsonMapper;

	private Page<TagBatch> getByFactoryUser(PageRequest pageable, UserDTO user, HttpServletRequest request,
											final String tagBatchIdOrName, final Integer type, final Integer formatStatus,
											final Integer associateStatus, Long factoryId) {
		String sql = "select tag.* from tag_batch tag ,tag_batch_config config where tag.tag_batch_config_id=config.id ";
		sql += " and config.print_factory_id=:factoryId";
		if (user.getEseId() != null & user.getEseId().intValue() != CommonConstants.SYSTEM_INNER_ESEID) {
			sql += " and tag.ese_id=:eseId";
		}
		if (type != null) {
			sql += " and tag.type=:type";
		}
		if (StringUtils.isNotBlank(tagBatchIdOrName)) {
			if (StringUtils.isNumeric(tagBatchIdOrName)) {
				sql += " and (tag.id=:tagbatchidorname or tag.name=:tagbatchidorname)";
			} else {
				sql += " and tag.name like %:tagbatchidorname%";
			}
		}
		sql += " order by id desc";
		Query query = em.createNativeQuery(sql, TagBatch.class);
		query.setParameter("factoryId", factoryId);
		if (user.getEseId() != null & user.getEseId().intValue() != CommonConstants.SYSTEM_INNER_ESEID) {
			query.setParameter("eseId", user.getEseId());
		}
		if (type != null) {
			query.setParameter("type", type);
		}
		if (StringUtils.isNotBlank(tagBatchIdOrName)) {
			query.setParameter("tagbatchidorname", tagBatchIdOrName);
		}
		int start = request.getParameter("start") == null ? 0 : Integer.parseInt(request.getParameter("start"));
		int end = request.getParameter("limit") == null ? 20 : Integer.parseInt(request.getParameter("limit")) + 20;
		query.setFirstResult(start);
		query.setMaxResults(end);
		List<TagBatch> tem = query.getResultList();
		Page<TagBatch> page = new PageImpl<TagBatch>(tem, pageable, query.getResultList().size());
		page.getContent();
		return page;
	}

	/**
	 * 标签批次下载接口
	 *
	 * @param user
	 * @param tagBatchId
	 * @return
	 */
	@ApiOperation(value = "标签批次下载接口", notes = "用户下载指定标签批次")
	@ApiImplicitParam(name = "tagBatchId", value = "批次ID", required = true, dataType = "Long", paramType = "path")
	@RequiresAuthentication
	@ButtonResource(cls = "", url = "download")
	@RequiresPermissions("code.download")
	@GetMapping(value = "download/{tagBatchId}")
	public void download(@PathVariable Long tagBatchId, HttpServletResponse response) {
		tagBatchService.downloadFile(tagBatchId, response);
	}
}
